package no.ffi.gismoidm.pubsub;

import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;

/**
 * This class behaves like a hash set, but has only a limited number of
 * member elements. When exceeding this maximum limit, the oldest
 * member is deleted
 * 
 * @author anders
 */
public class ExpiringHashSet implements java.util.Set {
    private LinkedHashSet hs;
    private int minLimit, maxLimit; // Minimum and maximum number of retained elements
    
    public ExpiringHashSet(int minLimit, int maxLimit) {
        this.maxLimit = maxLimit;
        this.minLimit = minLimit;
        hs = new LinkedHashSet(maxLimit+2);
    }

    @Override
    public int size() { return hs.size(); }

    @Override
    public boolean isEmpty() { return hs.isEmpty(); }

    @Override
    public boolean contains(Object o) { return hs.contains(o); }

    @Override
    public Iterator iterator() { return hs.iterator(); }

    @Override
    public Object[] toArray() { return hs.toArray(); }

    @Override
    public Object[] toArray(Object[] a) { return hs.toArray(a); }

    @Override
    public boolean add(Object e) {
        boolean b = hs.add(e);
        trimSize();
        return b;
    }

    @Override
    public boolean remove(Object o) { return hs.remove(o); }

    @Override
    public boolean containsAll(Collection c) { return hs.containsAll(c); }

    @Override
    public boolean addAll(Collection c) { 
        boolean b = hs.addAll(c);
        trimSize();
        return b;
    }

    @Override
    public boolean retainAll(Collection c) { return hs.retainAll(c); }

    @Override
    public boolean removeAll(Collection c) { return hs.removeAll(c); }

    @Override
    public void clear() { hs.clear(); }
    
    // Trim elements down to minLimit of exceeding maxLimit. The
    // hysteresis is intrduced for performance reasons
    private void trimSize() {
        if (hs.size() > maxLimit) {
            System.out.print("Trimming away elements");
            Iterator it = hs.iterator();
            while (hs.size() > minLimit) {
                it.next();
                it.remove();
                System.out.print(".");
            }
            System.out.println("");
        }
    }
}
